#!/bin/sh
# the next line restarts using tclsh \
exec tclsh "$0" "$@"
##################################################################################
#
# PVCS-Tcl Adaptor
# 
#	Authors:    Martin Klaus, prototype version by Terry W. Loar
#
#	History: 	Revised from RCSTCL Adaptor -  8/19/96 
#				Integrated with SNiFF+ - 9/4/96 
#				1.0 Bugfix, CrossPlatform support - 4/2/97
#				1.1 - Functionality for Updating Workspaces added.
#				1.2 - Bug with creating multiple archive files fixed.
#				    - Bug with mutilated archive names on Windows fixed.
#				1.3 - SNiFF+ will complain if there's no PVCS installed.
#				
#	Limitation: Comments and Descriptions passed on to an archive during check-in
#				must not be seeded with quotes (singe, double, backward,...)
#						
#	Please report problems with the adapter to: sniff-support@takefive.co.at
#
##################################################################################

#------ constants --------------------------------------------------------
global gProg;
set gProg "pvcs.tcl";
global gPathVar;
catch {set gPathVar $env(PATH)};
if {$gPathVar == ""} { catch {set gPathVar $env(Path)}; };
 
global gPlatform;
set gPlatform [lindex [array get tcl_platform platform] 1]; 

global gOS;
set gOS [lindex [array get tcl_platform os] 1];

global gSniffDir;
catch {set gSniffDir $env(SNIFF_DIR)}

# Temporary path for log files
global TempPath;
switch $gPlatform {
	windows {
		catch {set TempPath $env(TMP)}
		catch {set TempPath $env(TEMP)}
		if {$TempPath == ""} {
		  puts stderr "$gProg: Neither TMP nor TEMP environment variable is set"
		  exit 1
		} 
	}
	unix {
		set TempPath "/tmp";
	}
	* {
		set TempPath ""
	}
}
 
 
#------ Mks toolkit on Windows ------------------------------------------
 
global gMksBinDir;
switch $gPlatform {
	windows {
		set gMksRootDir $env(ROOTDIR);
		set gMksBinDir $gMksRootDir\\mksnt
		if { ! [file isdirectory $gMksBinDir] } {
			puts stderr "$gProg: MKS toolkit not found";
			exit 1
		}
	}
	* {
		set gMksRootDir "";
	}
}


#------ tracing ----------------------------------------------------------

global gTraceFile gTraceFileName gLogFileName gTempCfgFile;
set gTraceFile "";
 
switch $gPlatform {
	windows {
		set gTraceFileName "$TempPath\\pvcs.tcl.log";
		set gLogFileName "$TempPath\\vlog.out";
		set gTempCfgFile "$TempPath\\temp.cfg";
	}
	unix {
		#set gTraceFileName "$TempPath/pvcs.tcl.log";
		set gTraceFileName "/Tools/pvcs/pvcs.tcl.log";
		set gLogFileName "/$TempPath/vlog.out";
		set gTempCfgFile "$TempPath/temp.cfg";
		regsub -all {//} $gLogFileName {/} gLogFileName
	}
	* {
		set gTraceFileName "pvcs.tcl.log";
		set gLogFileName "vlog.out";
		set gTempCfgFile "temp.cfg";
	}
}
 
proc trace_open {} \
{
	set _Fct "trace_open";
	global gTraceFile gTraceFileName gDebug;

	if { $gDebug > 0 } {
		set gTraceFile [open $gTraceFileName {WRONLY CREAT APPEND}];
		fconfigure $gTraceFile -buffering none;
	}
}
proc trace_close {} \
{
	global gTraceFile;

	if { $gTraceFile != "" } {
		close $gTraceFile;
	}
	set gTraceFile "";
}
proc _value {arg} \
{
	return $arg;
}
proc trace_print {args} \
{
	global gTraceFile;

	if { $gTraceFile != "" } {
		puts $gTraceFile "$args";
		flush $gTraceFile
	}
}
proc trace_var {args} \
{
	global gTraceFile;
 
	if { $gTraceFile == "" } {
		return;
	}
	set Line "";
	set VarNameList [uplevel {info locals}];
	foreach VarName $VarNameList {
		set Value [uplevel "_value \$$VarName"];
		set Line "$Line $VarName=$Value";
	}
	puts $gTraceFile "$Line";
}

#------ path name routines -------------------------------------------------
proc path_concat {Prefix Suffix} \
{
	global gPlatform;
	switch $gPlatform {
		windows {
			set Separator {\\};
		}
		unix {
			set Separator {/};
		}
		macintosh {
			set Separator {:};
		}
		* {
			puts stderr "path_concat: not supported platform=$platform";
		}
	}
	return "$Prefix$Separator$Suffix";
}

#---------------------------------------------------------------------------
proc for_pattern_do {File StartPattern StopPattern Block} \
{
	for_pattern_do_at $File $StartPattern $StopPattern $Block 1; 
}
proc for_pattern_do_at {File StartPattern StopPattern Block Uplevel} \
{
	set _Fct "for_pattern_do_level_at";

	#------ global variables referenced
	global errorCode errorInfo;

	#------ Variables inserted in caller's stack frame
	#	for use within 'Block'
	upvar $Uplevel LINE LINE;
	upvar $Uplevel PHASE PHASE;
	upvar $Uplevel LINENR LINENR;
	#	when start pattern detected:	0
	#	between start and stop pattern: 1
	#	when stop pattern detected:	2

	#------ local variables
	set CatchCode 0;
	set ReturnValue "";
	set Cmd "eval {$Block}";
	#	Note: $Block is enclosed by brackets!
	#	Otherwise, we would have the expansion:
	#		"uplevel 1 eval cmd1; cmd2"
	#	which is not intended!
	#	Note: since we executing the 'Block' in the
	#	caller's stack frame, we have to evaluate 'Block'
	#	in the local context.
	set Phase 0;
	set Line "";
	set LineNr 0;
	set NumRead 0;
	set SeenStartPattern 0;
	set SeenStopPattern 0;
	
	#------ loop over input lines, detect patterns and call 'Block'
	set NumRead [gets $File Line];
	while { ! [eof $File] && ! $SeenStopPattern } {
		if { $SeenStartPattern && ! $SeenStopPattern } {
			set Phase 1;
			set SeenStopPattern [ regexp -- $StopPattern $Line Dummy ];
			if { $SeenStopPattern } {
				set Phase 2;
			}
		}
		if { ! $SeenStartPattern } {
			set SeenStartPattern [ regexp -- $StartPattern $Line Dummy ];
			if { $SeenStartPattern } {
				set Phase 0;
			}
		}

		if { $SeenStartPattern } {
			#------ set variables for use in 'Block'
			incr LineNr;
			set LINENR $LineNr;
			set LINE $Line;
			set PHASE $Phase;
			#------ execute block
			set CatchCode [	catch {uplevel $Uplevel $Cmd} ReturnValue	];
			switch $CatchCode {
				0 { 
					#	ok
				}
				1 {
					#	error - prepare for reraise
					set savedErrorInfo $errorInfo;
					set savedErrorCode $errorCode;
					break;
				}
				2 {
					#	return out of block
				}
				3 {
					#	break out of block - stop
					break;
				}
				4 {
					#	continue out of block
				}
				* {
					#	unknown! XXX
				}
			}
		}

		if { ! $SeenStopPattern } {
			set NumRead [gets $File Line];
		}
	}

	#------ reraise error if one occured in 'Block'
	if { $CatchCode == 1 } {
		#	reraise error
		error $ReturnValue $errorInfo $errorCode;
	}
	return $ReturnValue;
}

proc string_normalize {String} \
{
	regsub -all -- "\[  \r\n\]+" $String " " String;
	set String [string trim $String];
	return $String;
}

#------ external execution ---------------------------------------------
proc unknown {args} \
{
	global errorCode;
	global gTraceFile;

	#puts $gTraceFile "unknown: exec >@stdout 2>@stderr $args";
	set Exception [catch "exec >@stdout 2>@stderr $args" BlockValue];
	#puts stderr "Exception=$Exception errorCode=$errorCode";
	set errorCode 0;
	if "$Exception" {
		switch [lindex $errorCode 0] {
		CHILDSTATUS {
			return [lindex $errorCode 2];
			}
		POSIX {
			puts stderr "unknown.exec: [lindex $errorCode 2]"; }
			return 255;
		}
	} else {
		return 0;
	}
}

#------ basic file/directory manipulation -------------------------

proc dirname {path} \
{
	return [file dirname $path];
}
 
proc mkdir {Path} \
{
	global gMksBinDir;
	global gPlatform;
	if { $gPlatform == "unix"} {
		unknown mkdir $Path;
	} else {
		unknown $gMksBinDir\\mkdir $Path;
	}
}
proc mkdir_p {Path} \
{
	global gMksBinDir;
	global gPlatform;
	if { $gPlatform == "unix"} {
		unknown mkdir -p $Path;
	} else {
		unknown $gMksBinDir\\mkdir -p $Path;
	}
}
 
proc rm {Path} \
{
	global gMksBinDir;
	global gPlatform;
	if { $gPlatform == "unix"} {
		unknown rm -rf $Path;
	} else {
		unknown $gMksBinDir\\rm -rf $Path;
	}
	#	exit status not depending on success/failure!
}
 
proc rm_r {Path} \
{
	global gMksBinDir;
	global gPlatform;
	if { $gPlatform == "unix"} {
		unknown rm -rf $Path;
	} else {
		unknown $gMksBinDir\\rm -rf $Path;
	}
	#	exit status not depending on success/failure!
}
 
proc chmod_writable {Path} \
{
	global gMksBinDir;
	global gPlatform;
	if { $gPlatform == "unix"} {
		unknown chmod a+w $Path;
	} else {
		unknown $gMksBinDir\\chmod a+w $Path;
	}
	return 0;
}
 
proc chmod_readonly {Path} \
{
	global gMksBinDir;
	global gPlatform;
	if { $gPlatform == "unix"} {
		unknown chmod a-w $Path;
	} else {
		unknown $gMksBinDir\\chmod a-w $Path;
	}
	return 0;
}


#
#	file_grep: searches text file for pattern and returns 
#	first matching line
#
proc file_grep {FileName Pattern} \
{
	set Line "";
	set File "";
	set Matched 0;
	set MatchingLine "";

	set File [open $FileName RDONLY];
	set NumRead [gets $File Line];
	while { ! [eof $File] && ! $Matched } {
		set Matched [regexp -- $Pattern $Line MatchingLine];
		if { $Matched } {
			continue;
		}
		set NumRead [gets $File Line];
	}
	close $File;
	return $Line;
}
 
 
proc file_text_extract {File StartPattern StopPattern } \
{
	set Line "";
	set NumRead 0;
	set SeenStartPattern 0;
	set SeenStopPattern 0;
	set NumRead [gets $File Line];

	while { ! [eof $File] && ! $SeenStopPattern } {
		if { ! $SeenStartPattern } {
			set SeenStartPattern [ regexp -- $StartPattern $Line Dummy ];
			if { $SeenStartPattern } {
				set NumRead [gets $File Line];
			}
		}
		if { $SeenStartPattern && ! $SeenStopPattern } {
			set SeenStopPattern [ regexp -- $StopPattern $Line Dummy ];
		}
		if { $SeenStartPattern && ! $SeenStopPattern } {
			puts stdout $Line;
		}
		if { ! $SeenStopPattern } {
			set NumRead [gets $File Line];
		}
	}
}


#------ pvcs helper functions


#	pvcs_get_field extracts field values from the PVCS file.
#	The extracted field (including its name) are returned.
#	If something fails, an empty string is returned.

proc pvcs_get_field {FileName Field} {
	set _Fct "pvcs_get_field"; trace_var;
	set TmpFile "vlog.out";
	set MatchingLine "";
	unknown vlog -q -xo$TmpFile $FileName ;
	set MatchingLine [file_grep $TmpFile $Field];
	rm $TmpFile;
	return $MatchingLine;
}


#	pvcs_get_head: complete
#	pvcs_get_head extracts the head revision number for 
#	the file 'FileName'.

proc pvcs_get_head {FileName} {
	set Match1 "";
	# Note: regsub does not allocate variable if no match found!
	set Head [pvcs_get_field $FileName "^Last trunk rev:"];
	regexp -- "^Last trunk rev: (.*)" $Head Match Match1;
	set Match1 [string trim $Match1];
	return $Match1;
}


proc pvcs_log_extract {ReposFilePath StartPattern StopPattern Block} {

	global gPlatform gLogFileName;
	
	switch $gPlatform {
		windows {
			regsub -all {\\} $ReposFilePath {\\\\} ReposFilePath;
			unknown vlog -q -i -xo$gLogFileName $ReposFilePath;
			set TmpFile [open $gLogFileName RDONLY];
		}
		unix {
			regsub -all {//} $ReposFilePath {/} ReposFilePath;
			set TmpFile [open "|vlog -q -i $ReposFilePath" RDONLY];
		}
	}
	
	for_pattern_do_at $TmpFile $StartPattern $StopPattern $Block 2;

	close $TmpFile;
	rm $gLogFileName;
}


proc extract_archive_suffix { ReposFile WorkFile } \
{
	set matchpos [string last $WorkFile $ReposFile];
	set rf_length [string length $ReposFile];
	set wf_length [string length $WorkFile];
	set startrange [expr $matchpos + $wf_length];

	if { $startrange < $rf_length } {
		set suffix [string range $ReposFile $startrange end];
	} else {
		set suffix ",v"
	}
		
	return $suffix;
}


proc char_repeat {N Char} {
	set String "";
	set I 0;
	while { $I < $N } {
		set String "$String$Char";
		incr I;
	}
	return $String;
}

# vlog start and stop patterns for version history 
global cDashedLine;
set cDashedLine [char_repeat 30 "-"];
global cEqualLine
set cEqualLine [char_repeat 30 "="];
 
##################################################################################
#  	SNiFF+ Call: pvcs_checkout
#
#	PVCS Call(s): get
#
#	Description: Perform the mapping of SNiFF+ to PVCS to check a file out of the 
#				 repository.
#
#	SNiFF+		Adaptor		PVCS	Description
# 	------    	-------		----	--------------- 
#	%U			UserID				Needed in $gTempCfgFile 
#	%L 			Lock		-L		Lock  (E | N)
#	%s 			ForceFlag	-q,-qn	Overwrite work files - quiet mode 
#	%V 			Revision	-R		SNiFF version - PVCS Revision 
#	%A 			ReposPath			Path to directory of repository 
#	%F 			WorkFile	 		Working File to be checked out 
#	%W 			WorkPath			Path to directory of WorkFile 
#
#	Internal Adaptor Calls: chmod_writable, extract_archive_suffix
#
#	Return:	0  - OK
#			!0 - NOK
#
##################################################################################

proc pvcs_checkout { UserID Lock ForceFlag Revision ReposPath WorkFile WorkPath } \
{
	set _Fct "pvcs_checkout"; trace_var; #puts stderr "@@@@ pvcs_checkout";
	trace_print "UserID: $UserID"
	trace_print "Lock: $Lock"
	trace_print "ForceFlage: $ForceFlag"
	trace_print "Revision: $Revision"
	trace_print "ReposPath: $ReposPath"
	trace_print "WorkFile: $WorkFile"
	trace_print "WorkPath: $WorkPath"

	global TempPath gTempCfgFile;

	set Suffix [extract_archive_suffix $ReposPath $WorkFile];
	set SuffixArg "-s+$Suffix";

	set isSymbolicLink 0;
	set symbolicFileName "";
 
	set ReposPath [dirname $ReposPath];

	if {$Lock == "C"} {
		set_config $UserID $WorkPath "VCSDir $ReposPath \nMultiLock";
	} else {
		set_config $UserID $WorkPath "VCSDir $ReposPath";
	}
	
	cd $WorkPath;

	if { $ForceFlag } {
		set ForceFlagArg "-q";
	} else {
		set ForceFlagArg "-qn";
	}

	if { $Revision != ""} {
		set RevisionArg "-r$Revision";
	} else {
		set RevisionArg "";
	}

	# test the files
	if {[file type $WorkFile] == "link"} {
		trace_print "$WorkFile is a symbolic link";
		set isSymbolicLink 1;
		set symbolicFileName [file readlink $WorkFile];
 
		# remove the symbolic link
		file delete -force $WorkFile;
	}
 
	if {$Lock == "E"} {
	
		set Status [unknown get -c$gTempCfgFile -l $ForceFlagArg $RevisionArg $SuffixArg $WorkFile];	

	} elseif { $Lock == "N" } {

		set Status [unknown get -c$gTempCfgFile $ForceFlagArg $RevisionArg $SuffixArg $WorkFile];

	} else {
		if {![unknown get -c$gTempCfgFile -l  $ForceFlagArg $RevisionArg $SuffixArg $WorkFile] } {
 
			set Status [chmod_writable $WorkFile];
		} else {
			set Status 1;
		}
	}
	
	#rm $gTempCfgFile;

	return $Status;
}
##################################################################################
#  	SNiFF+ Call: pvcs_create_repository_file 
#
#	PVCS Call(s): put
#
#	Description: Perform the mapping of SNiFF+ to PVCS to check a file into the 
#				 repository for the first time.
#
#	SNiFF+	Adaptor		 	PVCS	Description
# 	------  -------			----	--------------- 
#	%U		UserID					Needed in $gTempCfgFile 
#	%L 		Lock			-L		Check in, then check out with Lock 
#	%C		Comment			-M		Change description
#	%I 		Description		-T		Workfile description 
#	%S 		SymbolicName	-V		Symbolic version name 
#	%V 		Revision		-R		SNiFF version - PVCS Revision 
#	%A 		ReposPath				Path to directory of repository 
#	%F 		WorkFile	 			Working File to be checked in 
#	%W 		WorkPath				Path to directory of WorkFile 
#
#	Internal Adaptor Calls: path_concat, extract_archive_suffix
#
#	Return:	0   - OK
#			!0  - NOK
#
##################################################################################

proc pvcs_create_repository_file  { UserID Lock Comment Description	 SymbolicName 	\
									Revision ReposPath WorkFile	WorkPath } \
{
	set _Fct "pvcs_create_repository_file"; trace_var;
	# puts stderr "@@@@ pvcs_create_repository_file: ReposPath=$ReposPath WorkFile=$WorkFile WorkPath=$WorkPath" ;
	
	global TempPath gTempCfgFile;
	global gPlatform;
	
	set Suffix [extract_archive_suffix $ReposPath $WorkFile];
	set ReposPath [dirname $ReposPath]
	set_config $UserID $WorkPath "VCSDir $ReposPath";

	cd $WorkPath;
 
	if { $SymbolicName != "" } {
		set VersionNameArg "-v$SymbolicName";
	} else {
		set VersionNameArg "";
	}

	if { $Description == "" } {
		set DescriptionArg "*** empty description ***";
	} else {
		set DescriptionArg $Description;
	}

	if { $Lock == "E" } {
		set LockArg "-l";
	} else {
		set LockArg "-u";
	}

	if { $Revision != ""} {
		set RevisionArg "-r$Revision";
	} else {
		set RevisionArg "";
	}
	
	switch $gPlatform {
		windows { set DescriptionArg -t"$DescriptionArg"; 
				  set CommentArg	 -m"$Comment"; 
				  set SuffixArg		 -s"+$Suffix"; }
		unix 	{ set DescriptionArg "-t$DescriptionArg";
				  set CommentArg	 "-m$Comment";	
				  set SuffixArg 	 "-s+$Suffix"; }
	}

	 set Status [unknown put -c$gTempCfgFile -q -f $LockArg $CommentArg $DescriptionArg $RevisionArg $VersionNameArg $SuffixArg $WorkFile ];

# puts stderr "test";

	rm $gTempCfgFile;
	
	return $Status;
}

##################################################################################
#  	SNiFF+ Call: pvcs_checkin
#
#	PVCS Call(s): put
#
#	Description: Perform the mapping of SNiFF+ to PVCS to check a file into the 
#				 repository.
#
#	SNiFF+	Adaptor			PVCS	Description
# 	------  ---------		----	------------------
#	%U		UserID					Needed in $gTempCfgFile 
#	%L 		Lock			-L		Check in, then check out with Lock 
#	%b		BranchFlag		-FB		Force a branch
#	%C		Comment			-M		Change description
#	%S 		SymbolicName	-V		Symbolic version name 
#	%V 		Revision		-R		Specific revision
#	%A 		ReposPath				Path to directory of repository 
#	%F 		WorkFile	 			File to be checked in 
#	%W 		WorkPath				Path to directory of WorkFile 
#	%B		BranchName		-V		Symbolic branch name	-- added 24/03/1997
#
#	Internal Adaptor Calls: path_concat, pvcs_get_head, extract_archive_suffix
#
#	Return:	0 - OK
#			!0 - NOK
#
##################################################################################

proc pvcs_checkin { UserID Lock BranchFlag Comment SymbolicName \
					Revision ReposPath WorkFile WorkPath BranchName} \
{
	set _Fct "pvcs_checkin"; trace_var;
	# puts stderr "@@@ pvcs_checkin:  Com=$Comment SymName=$SymbolicName Rev=$Revision \
					RepPath=$ReposPath WFile=$WorkFile WPath=$WorkPath BrName=$BranchName"

	global TempPath gTempCfgFile;
	global gLogFileName gPlatform;

	set Suffix [extract_archive_suffix $ReposPath $WorkFile];

	set ReposPath [dirname $ReposPath];
	set_config $UserID $WorkPath "VCSDir $ReposPath";
	
	cd $WorkPath;
	
 	#------ handle symbolic version name
	if { $SymbolicName != "" } {
		set VersionNameArg -v$SymbolicName;
	} else {
		set VersionNameArg "";
	}

	#------ handle lock type
	if { $Lock == "E" } {
		set LockArg "-l";
	} else {
		set LockArg "-u";
	}

	#------ revision
	if { $Revision != ""} {
		set RevisionArg "-r$Revision";
	} else {
		set RevisionArg "";
	}
	
	switch $gPlatform {
		windows { set CommentArg -m"$Comment"; 
				  set SuffixArg  -s"+$Suffix"; }
		unix 	{ set CommentArg "-m$Comment"; 
				  set SuffixArg "-s+$Suffix"; }
	}			
	
	if { $BranchFlag } {
		# Lock repository file
		vcs -c$gTempCfgFile -q -xe$gLogFileName -l$Revision $SuffixArg $WorkFile;

		set Status [unknown put	-c$gTempCfgFile -q -f -fb $LockArg $CommentArg -v$BranchName $SuffixArg $WorkFile ];

		# PVCS cannot assign 2 version labels at once, so we do it with a separate command.
		if { $SymbolicName != "" } {
			vcs -c$gTempCfgFile -q -v$SymbolicName:$BranchName $SuffixArg $WorkFile;
		}
	} else {

		set Status [unknown put	-c$gTempCfgFile -q -f $LockArg $CommentArg $RevisionArg $VersionNameArg $SuffixArg $WorkFile ];
	}
	
	rm $gTempCfgFile;

	return $Status;
}

##################################################################################
#  	SNiFF+ Call: pvcs_lock
#
#	PVCS Call(s): vcs
#
#	Description: Perform the mapping of SNiFF+ to PVCS to lock a file in the 
#				 repository and make the work file writeable.
#
#	SNiFF+	Adaptor		PVCS	Description
# 	------	-------		----	--------------- 
#	%U		UserID				Needed in $gTempCfgFile 
#	%V 		Revision	-R		SNiFF version - PVCS Revision 
#	%A 		ReposPath			Path to directory of repository 
#	%F 		WorkFile	 		File to be locked
#	%W 		WorkPath			Path to directory of WorkFile 
#
#	Internal Adaptor Calls: path_concat, chmod_writable, extract_archive_suffix
#
#	Return:	0  - OK
#			!0 - NOK
#
##################################################################################

proc pvcs_lock { UserID Revision ReposPath WorkFile WorkPath } \
{
	set _Fct " pvcs_lock "; trace_var;
	#puts stderr "@@@@  pvcs_lock $UserID";

	global TempPath gTempCfgFile gPlatform;

	set Suffix [extract_archive_suffix $ReposPath $WorkFile];
	
	switch $gPlatform {
		windows { set SuffixArg  -s"+$Suffix"; }
		unix 	{ set SuffixArg "-s+$Suffix"; }
	}			

	set ReposPath [dirname $ReposPath];
	set_config $UserID $WorkPath "VCSDir $ReposPath";

	cd $WorkPath;

	set Status [ unknown vcs  -q -c$gTempCfgFile -l$Revision $SuffixArg $WorkFile];

	if { !$Status } {
		chmod_writable [path_concat $WorkPath $WorkFile];
		set Status 0;
	} else {
		set Status 1;
	}

	rm $gTempCfgFile;
 
	return $Status;
}

##################################################################################
#  	SNiFF+ Call: pvcs_set_work_file_readonly 
#
#	Description: Perform the mapping of SNiFF+ to Adaptor to make a workfile read-only.
#
#	SNiFF+	Adaptor		PVCS	Description
# 	------  ---------	----	--------------- 
#	%F 		WorkFile	 		File to be made read-only 
#	%W 		WorkPath			Path to directory of WorkFile 
#
#	Internal Adaptor Calls: path_concat, chmod_readonly 
#
#	Return:	0  - OK
#			!0 - NOK
#
##################################################################################

proc pvcs_set_work_file_readonly { WorkFile WorkPath } \
{
	set _Fct "pvcs_set_work_file_readonly"; trace_var; 
	#puts stderr "@@@@  pvcs_set_work_file_readonly ";

	set Status [chmod_readonly [path_concat $WorkPath $WorkFile]];

	return $Status;
}

##################################################################################
#  	SNiFF+ Call: pvcs_is_different 
#
#	PVCS Call(s): vdiff
#
#	Description: Perform the mapping of SNiFF+ to PVCS to check if there is 
#				 a difference between the current working file and a given version.
#
#	SNiFF+	Adaptor		 	PVCS	Description
# 	------  ---------		----	--------------- 
#	%A 		ReferenceFile			Full Path to reference (original) file 
#	%V 		Revision		-R		SNiFF version - PVCS Revision 
#	%F 		TargetFile 	 			File to be compared with reference file 
#	%W 		WorkPath				Path to directory of TargetFile 
#
#	Internal Adaptor Calls: path_concat, extract_archive_suffix
#
#	Return:	0 - Files are the same
#			1 - Error
#			2 - Files are different
#
##################################################################################

proc pvcs_is_different { ReferenceFile Revision TargetFile WorkPath } \
{
	set _Fct "pvcs_is_different"; trace_var; 
	#puts stderr "@@@@  pvcs_is_different";

	global gPlatform;
	
	set Suffix [extract_archive_suffix $ReferenceFile $TargetFile];

	switch $gPlatform {
		windows { set SuffixArg  -s"+$Suffix"; }
		unix 	{ set SuffixArg "-s+$Suffix"; }
	}			

	cd $WorkPath;

	set Status [unknown vdiff -q -T -r$Revision $SuffixArg $ReferenceFile $TargetFile ];
	
	return $Status;
}

##################################################################################
#  	SNiFF+ Call: pvcs_diff_text_w_v
#
#	Description: Perform the mapping of SNiFF+ to PVCS to compare the current 
#				 working file with a given version. Put the differences in DeltaFile.
#
#	SNiFF+	Adaptor			PVCS	Description
# 	------  ---------		-----	--------------- 
#	%T 		TempFile	 			Full path to temporary file 
#	%A 		ReferenceFile			Full path to reference (original) file 
#	%V 		Revision		-R		SNiFF version - PVCS Revision 
#	%F 		TargetFile 	 			File to be compared with reference file 
#	%W 		WorkPath				Path to directory of WorkFile 
#
#	Internal Adaptor Calls: path_concat 
#
#	Return:	0  - OK
#			!0 - NOK
#
##################################################################################

proc pvcs_diff_text_w_v { TempFile ReferenceFile Revision TargetFile WorkPath } \
{
	set _Fct "pvcs_diff_text_w_v"; trace_var;
		
	get -q -r$Revision $ReferenceFile\($TempFile\);
	
	cd $WorkPath;
	set Status [unknown diff -b $TargetFile $TempFile ];
	
	return $Status;
}

##################################################################################
#  	SNiFF+ Call: pvcs_diff_text_v_v
#
#	Description: Perform the mapping of SNiFF+ to PVCS to compare two revisions 
#				 of an archived file. Put the differences in DeltaFile.
#
#	SNiFF+	Adaptor			PVCS	Description
# 	------  -------			----	--------------- 
#	%T 		TempFile	 			Full path to temporary file 
#	%A 		ReferenceFile			Full path to archived file 
#	%V 		Rev1			-R		SNiFF version - PVCS 1st Revision 
#	%v 		Rev2			-R		SNiFF version - PVCS 2nd Revision 
#
#	Internal Adaptor Calls: path_concat 
#
#	Return:	0  - OK
#			!0 - NOK
#
##################################################################################

proc pvcs_diff_text_v_v { TempFile ReferenceFile Rev1 Rev2 } \
{
 
	set _Fct " pvcs_diff_text_v_v "; trace_var; 
	#puts stderr "@@@ pvcs_diff_text_v_v TempF=$TempFile RevF=$ReferenceFile Rev1=$Rev1 Rev2=$Rev2";

	global gPlatform;

	switch $gPlatform {
		unix {
			regsub -all {//} $TempFile {/} TempFile;
			regsub -all {//} $ReferenceFile {/} ReferenceFile;
		}
		* { }
	}

	get  -q -r$Rev1 $ReferenceFile\($TempFile\_$Rev1\);
	get  -q -r$Rev2 $ReferenceFile\($TempFile\_$Rev2\);
	set Status [ unknown diff -b $TempFile\_$Rev1 $TempFile\_$Rev2 ];

	return $Status;
}

##################################################################################
#	pvcs_update_project: not supported XXX

proc pvcs_update_project {} {
	set _Fct "pvcs_update_project"; trace_var;
	puts stderr "$_Fct: no workspace support";
	return 0;
}

##################################################################################
#  	SNiFF+ Call: pvcs_update_file
#
#	PVCS Call(s): through sniffUpdateFile.PVCS.sh: get, vdiff
#
#	Description: Perform the mapping of SNiFF+ to PVCS to update a file.
#
#	SNiFF+	Adaptor		PVCS	Description
# 	------	---------	----	--------------- 
#	%d		SniffDir			Path to $SNIFF_DIR
#	%W 		WorkDir				Path to directory of WorkFile 
#	%f		FileDir				Path to FileName
#	%F 		FileName	 		Workfile name
#	%A 		ReposFile			Path to repository file
#	%V 		Revision	-R		SNiFF version - PVCS Revision 
#	%G		SSWSRoot			Path to Shared Source Workspace
#	%g		SOWSRoot			Path to Shared Object Workspace
#
#	Return:	0  - OK
#			!0 - NOK
#
##################################################################################

proc pvcs_update_file { WorkDir FileDir FileName \
						ReposFile Revision SSWSRoot SOWSRoot System Delimiter Nulldevice } \
{
	set _Fct "pvcs_update_file"; trace_var;

	global gPlatform gSniffDir;
	
	if { $Revision != "" } {
		set VersionArg "-r $Revision";	# This is how the shell script expects the
	} else {							# revision number, and not PVCS!
		set VersionArg "";
	}

	if { $gPlatform == "windows" } {
			regsub -all {\\} $WorkDir 	{/} WorkDir;
			regsub -all {\\} $FileDir 	{/} FileDir;
			regsub -all {\\} $ReposFile {/} ReposFile;
			regsub -all {\\} $SSWSRoot 	{/} SSWSRoot;
			regsub -all {\\} $SOWSRoot 	{/} SOWSRoot; 
	}	

	if { $gPlatform == "windows" } {
		if { $Revision != "" } {
			set Status [unknown sh $gSniffDir/bin/sniffUpdateFile.PVCS.sh \
									\"$WorkDir\" \"$FileDir\" \"$FileName\" \
									\"$ReposFile\" \"-r\" \"$Revision\" \"$SSWSRoot\" \"$SOWSRoot\" \"$System\" \"$Delimiter\" \"$Nulldevice\" ];
		} else {
			set Status [unknown sh $gSniffDir/bin/sniffUpdateFile.PVCS.sh \
									\"$WorkDir\" \"$FileDir\" \"$FileName\" \
									\"$ReposFile\" \"$SSWSRoot\" \"$SOWSRoot\" \"$System\" \"$Delimiter\" \"$Nulldevice\" ];
		}
	} else {
		if { $Revision != "" } {
			set Status [unknown sh $gSniffDir/bin/sniffUpdateFile.PVCS.sh \
									$WorkDir $FileDir $FileName $ReposFile -r $Revision $SSWSRoot $SOWSRoot $System $Delimiter $Nulldevice ];
		} else {
			set Status [unknown sh $gSniffDir/bin/sniffUpdateFile.PVCS.sh \
									$WorkDir $FileDir $FileName $ReposFile $SSWSRoot $SOWSRoot $System $Delimiter $Nulldevice ];
		}	
	}

	return $Status;
}

##################################################################################
#  	SNiFF+ Call: pvcs_unlock
#
#	PVCS Call(s): vcs
#
#	Description: Perform the mapping of SNiFF+ to PVCS to unlock a file in the 
#				 repository and make the work file read-only.
#
#	SNiFF+	Adaptor		PVCS	Description
# 	------	---------	----	--------------- 
#	%U		UserID				Needed in gTempCfgFile 
#	%V 		Revision	-R		SNiFF version - PVCS Revision 
#	%A 		ReposPath			Path to directory of repository 
#	%F 		WorkFile	 		File to be unlocked
#	%W 		WorkPath			Path to directory of WorkFile 
#
#	Internal Adaptor Calls: path_concat, chmod_readonly, extract_archive_suffix
#
#	Return:	0  - OK
#			!0 - NOK
#
##################################################################################

proc pvcs_unlock { UserID Revision ReposPath WorkFile WorkPath } \
{
	set _Fct " pvcs_lock "; trace_var;
	#puts stderr "@@@@  pvcs_unlock ";

	global TempPath gTempCfgFile gPlatform;

	set Suffix [extract_archive_suffix $ReposPath $WorkFile];

	switch $gPlatform {
		windows { set SuffixArg  -s"+$Suffix"; }
		unix 	{ set SuffixArg "-s+$Suffix"; }
	}			

	set ReposPath [dirname $ReposPath];
	set_config $UserID $WorkPath "VCSDir $ReposPath";

	cd $WorkPath;

	set Status [unknown vcs  -q -c$gTempCfgFile -r$Revision -u:$UserID $SuffixArg $WorkFile];

	if { !$Status } {
		chmod_readonly [path_concat $WorkPath $WorkFile];
		set Status 0;
	} else {
		set Status 1;
	}
 
	rm $gTempCfgFile;

	return $Status;
}
################################################################################## 
#  	SNiFF+ Call: pvcs_break_lock
#
#	PVCS Call(s): vcs
#
#	Description: Perform the mapping of SNiFF+ to PVCS to break the lock on a 
#				 user's version of a file.
#
#	SNiFF+	Adaptor		 	PVCS	Description
# 	------	---------		----	--------------- 
#	%V 		Version			-R		Revision
#	%A 		ReposFilePath			Absoulte Path to File 
#
#	Return:	0  - OK
#			!0 - NOK
#
##################################################################################

proc pvcs_break_lock { Revision ReposFilePath } \
{
	set _Fct "pvcs_break_lock"; trace_var; 
	#puts stderr "@@@@  pvcs_break_lock ";
	
	global gPlatform gLogFileName;
	
	switch $gPlatform {
		windows {
			regsub -all {\\} $ReposFilePath {\\\\} ReposFilePath;
			unknown vlog -q -bl -xo$gLogFileName $ReposFilePath;
			set TmpFile [open $gLogFileName RDONLY];
		}
		unix {
			regsub -all {//} $ReposFilePath {/} ReposFilePath;
			set TmpFile [open "|vlog -q -bl $ReposFilePath" RDONLY];
		}
	}

	gets $TmpFile Status;
	scan $Status {%s %s %s} FileName SepBar UserName;

	set Status [unknown vcs -q -r$Revision -u:$UserName $ReposFilePath ];
	
	close $TmpFile;
	rm $gLogFileName;
	
	return $Status;
}

##################################################################################
#  	SNiFF+ Call: pvcs_delete_version 
#
#	PVCS Call(s): vdel
#
#	Description: Perform the mapping of SNiFF+ to PVCS to delete a revision of a file 
#				 in the repository. This does not revert subsequent revisions. It 
#				 simply removes the record of the revision in the log.
#
#	SNiFF+	Adaptor			PVCS	Description
# 	------  ---------		----	--------------- 
#	%V 		Revision		-R		SNiFF version - PVCS Revision 
#	%A 		ReposFilePath			Absoulte path to archived file 
#
#	Internal Adaptor Calls: path_concat 
#
#	Return:	0  - OK
#			!0 - NOK
#
##################################################################################

proc pvcs_delete_version { Revision ReposFilePath } \
{
	set _Fct " pvcs_delete_version "; trace_var; 
	#puts stderr "@@@@  pvcs_delete_version ";

	if { $Revision == "" } {
		set Revision [pvcs_get_head $ReposFilePath ];
	}
	
	set Status [unknown vdel -q -r$Revision $ReposFilePath ];

	return $Status;
}

##################################################################################
#  	SNiFF+ Call: pvcs_set_description
#
#	PVCS Call(s): vcs
#
#	Description: Perform the mapping of SNiFF+ to PVCS to specify the description 
#				 of  a version of a file in the repository.
#
#	SNiFF+	Adaptor		 	PVCS	Description
# 	------  ---------		----	--------------- 
#	%I 		Description		-M		Description Text 
#	%A 		ReposFilePath			Absoulte Path to File
#
#	Return:	0  - OK
#			!0 - NOK
#
##################################################################################

proc pvcs_set_description { Description ReposFilePath } \
{
	set _Fct " pvcs_set_description "; trace_var; 
	#puts stderr "@@@@  pvcs_set_description "; 
	
	global gPlatform;

	set Description [string trimright $Description];
	switch $gPlatform {
		windows { set DescriptionArg -t"$Description"; }
		unix 	{ set DescriptionArg "-t$Description"; }			
	}
	
	set Status [unknown vcs	-q $DescriptionArg $ReposFilePath ];

	return $Status
}

##################################################################################
#  	SNiFF+ Call: pvcs_set_symbol 
#
#	PVCS Call(s): vcs
#
#	Description: Perform the mapping of SNiFF+ to PVCS to associate a symbol with 
#				 the version of a file in the repository. Overwrite existing symbol, 
#				 if any.
#
#	SNiFF+	Adaptor		 	PVCS	Description
# 	------  ---------		----	--------------- 
#	%S 		SymbolicName	-V		Symbolic version name 
#	%s 		ForceFlag		-q,-qn	Force change - quiet mode 
#	%V 		Revision		-R		SNiFF version - PVCS Revision 
#	%A 		ReposFilePath			Absoulte Path to File 
#
#	Return:	0  - OK
#			!0 - NOK
#
##################################################################################

proc pvcs_set_symbol { SymbolicName ForceFlag Revision ReposFilePath } \
{
	set _Fct "pvcs_set_symbol"; trace_var; 
	#puts stderr "@@@@  pvcs_set_symbol $SymbolicName to $ReposFilePath";

	if { $ForceFlag } {
		set ForceFlagArg -q;
	} else {
		set ForceFlagArg -qn;
	}

	if {$Revision == ""} {
		set Status [unknown vcs	$ForceFlagArg -v$SymbolicName $ReposFilePath ];

	} else {
		set Revision [string trim $Revision];
		set Status [unknown vcs $ForceFlagArg -r$Revision -v$SymbolicName $ReposFilePath ];
	}

	return $Status;
}

##################################################################################
#  	SNiFF+ Call: pvcs_delete_symbol 
#
#	PVCS Call(s): vcs
#
#	Description: Perform the mapping of SNiFF+ to PVCS to disassociate a symbol 
#				 from the version of a file in the repository.
#
#	SNiFF+	Adaptor			PVCS	Description
# 	------  ---------		----	--------------- 
#	%S 		SymbolicName	-V		Symbolic version name 
#	%A 		ReposFilePath			Absoulte Path to File
#
#	Return:	0  - OK
#			!0 - NOK
#
##################################################################################

proc pvcs_delete_symbol { SymbolicName ReposFilePath } \
{	
	set _Fct "pvcs_delete_symbol"; trace_var; 
	#puts stderr "@@@@  pvcs_delete_symbol "; 
 
	set Status [unknown vcs	-q -v$SymbolicName:delete $ReposFilePath ];

	return $Status
}

##################################################################################
#  	SNiFF+ Call: pvcs_change_comment 
#
#	PVCS Call(s): vcs
#
#	Description: Perform the mapping of SNiFF+ to PVCS to change a version's comment 
#				 in a file in the repository.
#
#	SNiFF+	Adaptor		 	PVCS	Description
# 	-----   ---------		----	--------------- 
#	%C 		Comment			-M		New Comment
#	%V 		Revision		-R		SNiFF version - PVCS Revision 
#	%A 		ReposFilePath			Absoulte Path to File
#
#	Return:	0  - OK
#			!0 - NOK
#
##################################################################################

proc pvcs_change_comment { Comment Revision ReposFilePath } \
{
	set _Fct "pvcs_change_comment"; trace_var; 
	#puts stderr "@@@@  pvcs_change_comment "; 
	
	set Status [unknown vcs -q -m"$Comment" -r$Revision $ReposFilePath ];			

	return $Status
}

##################################################################################
#  	SNiFF+ Call: pvcs_description
#
#	PVCS Call(s): vcs
#
#	Description: Perform the mapping of SNiFF+ to PVCS to get the description text 
#				 of a file in the repository.
#
#	SNiFF+	Adaptor		 	PVCS	Description
# 	------  ---------		----	--------------- 
#	%A 		ReposFilePath			Absoulte Path to File 
#
#	Return:	0  - OK
#			!0 - NOK
#
################################################################################## 

proc pvcs_description { ReposFilePath } \
{
	set _Fct "pvcs_description"; trace_var; 
	#puts stderr "@@@@  pvcs_description ";
	
	global cDashedLine;	
	global gPlatform gLogFileName;
	
	switch $gPlatform {
		windows {
			unknown vlog -q -i -xo$gLogFileName $ReposFilePath;
			set TmpFile [open $gLogFileName RDONLY];
		}
		unix {
			set TmpFile [open "|vlog -q -i $ReposFilePath" RDONLY];
		}
	}

	while { ! [eof $TmpFile] } {
		file_text_extract $TmpFile "^Description:" "^$cDashedLine";
	}
	
	close $TmpFile;
	rm $gLogFileName;

	return 0;
}

##################################################################################
#  	SNiFF+ Call: pvcs_history 
#
#	PVCS Call(s): vcs
#
#	Description: Perform the mapping of SNiFF+ to PVCS to get the version control 
#				 history of a file in the repository.
#
#	SNiFF+	Adaptor			PVCS	Description
# 	------  ---------		----	--------------- 
#	%A 		ReposFilePath			Absoulte Path to File 
#
#	Return:	0  - OK
#			!0 - NOK
#
##################################################################################

proc pvcs_history { ReposFilePath } \
{
	set _Fct "pvcs_history"; trace_var;
	#puts stderr "@@@@  pvcs_history ";
 
	global cDashedLine cEqualLine;
	global gPlatform gLogFileName;
	
	switch $gPlatform {
		windows {
			unknown vlog -q -i -xo$gLogFileName $ReposFilePath;
			set TmpFile [open $gLogFileName RDONLY];
		}
		unix {
			set TmpFile [open "|vlog -q -i $ReposFilePath" RDONLY];
		}
	}

	while { ! [eof $TmpFile] } {
		file_text_extract $TmpFile "^$cDashedLine" "^$cEqualLine" ;
	}
	
	close $TmpFile;
	rm $gLogFileName;

	return 0;
}

##################################################################################
#  	SNiFF+ Call: pvcs_head
#
#	PVCS Call(s): vlog (indirect)
#
#	Description: Perform the mapping of SNiFF+ to PVCS to show the HEAD revision 
#				 of the main branch of the repository.
#
#	SNiFF+	Adaptor			PVCS	Description
# 	------  ---------		----	--------------- 
#	%A 		ReposFilePath			Absoulte Path to File 
#
#	Internal Adaptor Calls: pvcs_get_head 
#
#	Return:	0  - OK
#			!0 - NOK
#
################################################################################## 

proc pvcs_head { ReposFilePath } \
{
	set _Fct "pvcs_head"; trace_var;
	#puts stderr "@@@@  pvcs_head ";

	set Status [pvcs_get_head $ReposFilePath];
	puts stdout $Status;
	
	return 0;
}

##################################################################################
# 	pvcs_symbol_list_one 	
#
#	Description: Service procedure for pvcs_symbol_list .
#
#	SNiFF+	Adaptor			PVCS	Description
# 	------  ---------		----	--------------- 
#	%A 		ReposFilePath			Absoulte Path to File 
#
#	Internal Adaptor Calls: string_normalize 
#
#	Return:	0  - OK
#			!0 - NOK
#
################################################################################## 

proc pvcs_symbol_list_one { ReposFilePath } \
{
	# puts stderr "@@@@  pvcs_symbol_list_one ";

	global gLogFileName;
	set File "";

	set Status [unknown vlog -q -i -xo$gLogFileName $ReposFilePath ];
	
	if {!$Status} {	
	set File [open $gLogFileName RDONLY];

	for_pattern_do $File "^Workfile:" "" {
		regexp -- "^Workfile: (.*)" $LINE Match WorkingFile;
		set WorkingFile [string_normalize $WorkingFile];
		puts stdout "$WorkingFile";
		break;
	}
	for_pattern_do $File "^Last trunk rev:" "" {
		regexp -- "^Last trunk rev: (.*)" $LINE Match Head;
		set Head [string_normalize $Head];
		puts stdout "HEAD: $Head";
		break;
	}
	for_pattern_do $File "^Version labels:" "^Description:" {
		if { $PHASE == 1 } {
			set Line [string_normalize $LINE];
			regsub -all {"} $Line {} Line;
			regsub -all { =} $Line {:} Line;
			puts stdout "$Line";
		}
	}
	while { ! [eof $File] } {
		for_pattern_do $File "^Rev" "" {
			if {![string match *count* $LINE]} {
				set Line [string_normalize $LINE];
				set Revision [lindex $Line 1];
				puts -nonewline stdout "$Revision ";
				break;
			}
		}
		for_pattern_do $File "^Checked in:" "" {
			set Line [string_normalize $LINE];
			puts -nonewline stdout [			\
				format " %s/%s/%s %s;"	\
					[lindex $Line 4]	\
					[lindex $Line 3]	\
					[lindex $Line 2]	\
					[lindex $Line 5]	\
			];
			break;
		}
		for_pattern_do $File "^Author id" "" {
			set Line [string_normalize $LINE];
			puts stdout [			\
				format " %s;" [lindex $Line 2]	\
			];
			break;
		}
	}
	close $File;
	rm $gLogFileName;
	}

	return $Status;
}

##################################################################################
#  	SNiFF+ Call: pvcs_symbol_list
#
#	PVCS Call(s): vlog (indirect)
#
#	Description: Perform the mapping of SNiFF+ to PVCS to show a complete history 
#				 of a file with all its revisions and symbols.
#
#	SNiFF+	Adaptor		 	PVCS	Description
# 	------  ---------		----	--------------- 
#	%A 		ReposFilePath			Absoulte Path to File 
#
#	Internal Adaptor Calls: pvcs_symbol_list_one 
#
#	Return:	0  - OK
#			!0 - NOK
#
################################################################################## 

proc pvcs_symbol_list { ReposFilePath } \
{
	set _Fct "pvcs_symbol_list"; trace_var; 
	# puts stderr "@@@@  pvcs_symbol_list $ReposFilePath";

	regsub -all {\\} $ReposFilePath {\\\\} ReposFilePath;
	
	foreach File $ReposFilePath {
		puts -nonewline stdout "\f";
		pvcs_symbol_list_one $File;
	}
	return 0;
}

##################################################################################
#  	SNiFF+ Call: pvcs_revision_of_symbol 
#
#	PVCS Call(s): vlog (indirect)
#
#	Description: Perform the mapping of SNiFF+ to PVCS to show the revision of a 
#				 of a file that a symbol is associated with.
#
#	SNiFF+	Adaptor		 	PVCS	Description
# 	------  ---------		----	--------------- 
#	%S 		SymbolicName	-V		Symbolic name of revision 
#	%A 		ReposFilePath			Absoulte Path to File 
#
#	Internal Adaptor Calls: pvcs_log_extract, pvcs_get_head, string_normalize 
#
#	Return:	0  - OK
#			!0 - NOK
#
##################################################################################

proc pvcs_revision_of_symbol { SymbolicName ReposFilePath } \
{
	set _Fct "pvcs_revision_of_symbol"; trace_var; 
	#puts stderr "@@@@  pvcs_revision_of_symbol ";

	if { $SymbolicName == "HEAD" } {
		pvcs_get_head $ReposFilePath;
	} else {
		pvcs_log_extract $ReposFilePath	"$SymbolicName"	"^Description:"	\
		{
			if { $PHASE == 0 } {
				set Line [string_normalize $LINE];
				puts stdout "[lindex $Line 2]";
				break;
			}
		}
	}

	return 0;
}

##################################################################################
#  	SNiFF+ Call: pvcs_history_of_revision 
#
#	PVCS Call(s): vlog
#
#	Description: Perform the mapping of SNiFF+ to PVCS to show the history of a 
#				 sprecific version of a file.
#
#	SNiFF+	Adaptor		 	PVCS	Description
# 	------  ---------		----	--------------- 
#	%V 		Revision		-R		SNiFF version - PVCS Revision 
#	%A 		ReposFilePath			Absoulte Path to File 
#
#	Return:	0  - OK
#			!0 - NOK
#
##################################################################################

proc pvcs_history_of_revision {	Revision ReposFilePath } \
{	
	set _Fct "pvcs_history_of_revision"; trace_var; 
	#puts stderr "@@@@  pvcs_history_of_revision ";

	global cDashedLine cEqualLine;
	global gPlatform gLogFileName;
	
	switch $gPlatform {
		windows {
			unknown vlog -q -i -xo$gLogFileName $ReposFilePath;
			set TmpFile [open $gLogFileName RDONLY];
		}
		unix {
			set TmpFile [open "|vlog -q -i $ReposFilePath" RDONLY];
		}
	}

	# $Revision could contain a version label. We check this here:
	set Status 0;
	regexp -- "SNIFF_BRANCH|SNIFF_CHANGESET" $Revision Status;

	if { $Status != 0 } \
	{	
		# set Revision to revision number corresponding to version label.
		for_pattern_do_at $TmpFile "$Revision" "^Description:" { if { $PHASE <= 1 } { break; } } 1;
		set Revision [lindex $LINE 2];
	}

	# extract history for revision.
	for_pattern_do $TmpFile "^Rev $Revision" "$cDashedLine|$cEqualLine" \
	{
		if { $PHASE <= 1 } { puts stdout "$LINE"; }
	};

	close $TmpFile;
	rm $gLogFileName;
	
	return 0;
}

##################################################################################
#  	SNiFF+ Call: pvcs_comment
#
#	PVCS Call(s): vlog
#
#	Description: Perform the mapping of SNiFF+ to PVCS to show the commment for the 
#				 specific version of a file.
#
#	SNiFF+	Adaptor		 	PVCS	Description
# 	------  ---------		----	--------------- 
#	%V 		Revision		-R		SNiFF version - PVCS Revision 
#	%A 		ReposFilePath			Absoulte Path to File 
#
#	Internal Adaptor Calls: pvcs_log_extract 
#
#	Return:	0  - OK
#			!0 - NOK
#
##################################################################################

proc pvcs_comment { Revision ReposFilePath } \
{
	set _Fct "pvcs_comment"; trace_var;
	#puts stderr "@@@@  pvcs_comment ";

	global cDashedLine cEqualLine;
	global gPlatform gLogFileName;
	
	switch $gPlatform {
		windows {
			unknown vlog -q -i -xo$gLogFileName $ReposFilePath;
			set TmpFile [open $gLogFileName RDONLY];
		}
		unix {
			set TmpFile [open "|vlog -q -i $ReposFilePath" RDONLY];
		}
	}

	# ----- $Revision could contain a version label. We check this here:
	set Status 0;
	regexp -- "SNIFF_BRANCH|SNIFF_CHANGESET" $Revision Status;

	if { $Status != 0 } \
	{	
		# set Revision to revision number corresponding to version label.
		for_pattern_do_at $TmpFile "$Revision" "^Description:" { if { $PHASE <= 1 } { break; } } 1;
		set Revision [lindex $LINE 2];
	}

	# ----- extract history for revision.
	for_pattern_do $TmpFile "^Rev $Revision" "$cDashedLine|$cEqualLine" \
	{
		# puts stderr "PHASE=$PHASE LINENR=$LINENR LINE=\"$LINE\"";
		if { $PHASE == 1 } {
			if { $LINENR >= 1 && [regexp -- "^Locked by" $LINE d1] } {
				continue;
			}
			if { $LINENR >= 3 && [regexp -- "^Branches:" $LINE d1] } {
				continue;
			}
			if { $LINENR >= 3 && [regexp -- "^Last modified" $LINE d1] } {
				continue;
			}
			if { $LINENR >= 3 && [regexp -- "^Author id:" $LINE d1] } {
				continue;
			}
			if { $LINENR > 3 } {
				puts stdout "$LINE";
			}
		}
	}

	close $TmpFile;
	rm $gLogFileName;

	return 0;
}

##################################################################################
#  	SNiFF+ Call: pvcs_lockers
#
#	PVCS Call(s): vlog
#
#	Description: Perform the mapping of SNiFF+ to PVCS to show the locker and the 
#				 version of a file.
#
#	SNiFF+	Adaptor			PVCS	Description
# 	------  ---------		----	--------------- 
#	%A 		ReposFilePath			Absoulte Path to File
#
#	Return:	0  - OK
#			!0 - NOK
#
##################################################################################

proc pvcs_lockers {	ReposFilePath } \
{
	set _Fct "pvcs_lockers"; trace_var;
	
	global gPlatform gLogFileName;

	switch $gPlatform {
		windows {
			regsub -all {\\} $ReposFilePath {\\\\} ReposFilePath;
			unknown vlog -q -i -xo$gLogFileName $ReposFilePath;
			set TmpFile [open $gLogFileName RDONLY];
		}
		unix {
			regsub -all {//} $ReposFilePath {/} ReposFilePath;
			set TmpFile [open "|vlog -q -i $ReposFilePath" RDONLY];
		}
	}

	while { ! [eof $TmpFile] } {
		for_pattern_do $TmpFile "^Workfile: " "" {
			regexp -- "^Workfile: (.*)" $LINE Match WorkingFile;
			puts -nonewline "[string trimleft $WorkingFile] ";	
			break;
		}
		for_pattern_do $TmpFile "^Locks:" "^Groups:" {
			set Line [string trimleft $LINE \n];
			regsub -all {Locks:} $Line {} Line ;
			regsub -all {Groups:} $Line {} Line ;
			set Line [string_normalize $Line];
			# sniff cannot deal with leading tab as white space
			if { [string length $Line ] != 0 } {
				puts -nonewline stdout " $Line";
			}
		}
		puts stdout "";
	}
	
	close $TmpFile;
	rm $gLogFileName;

	return 0;
}
 
##################################################################################
#  	SNiFF+ Call: pvcs_is_locked_by
#
#	PVCS Call(s): vlog
#
#	Description: Perform the mapping of SNiFF+ to PVCS to determine if a file is 
#				 locked by a specific user.
#
#	SNiFF+	Adaptor		 	PVCS	Description
# 	------  -------			----	--------------- 
#	%U 		User					User
#	%A 		ReposFilePath			Absoulte Path to File 
#
#	Return:	0  - OK
#			!0 - NOK
#
##################################################################################

proc pvcs_is_locked_by { User ReposFilePath } \
{
	set _Fct "pvcs_is_locked_by"; trace_var; 
	# puts stderr "@@@@  pvcs_is_locked_by ";

	global gLogFileName;
	
	set Status [unknown vlog -q -bl$User -xo$gLogFileName $ReposFilePath ];

	if {! $Status } \
	{
		set FileSize [file size $gLogFileName];
		rm $gLogFileName;
		if { $FileSize > 0 } {
			set Status 0;
		} else {
			set Status  1;
		}
	}

	return $Status;
}

##################################################################################
#  	SNiFF+ Call: pvcs_is_locked
#
#	PVCS Call(s): vlog
#
#	Description: Perform the mapping of SNiFF+ to PVCS to determine if a file is locked 
#				 by any user.
#
#	SNiFF+	Adaptor			PVCS			Description
# 	------  ---------		----------		--------------- 
#	%A 		ReposFilePath					Absoulte Path to File
#
#	Return:	0 - Locked
#			1 - Not locked
#
##################################################################################

proc pvcs_is_locked { ReposFilePath} \
{
	set _Fct "pvcs_is_locked"; trace_var;
	#puts stderr "@@@@  pvcs_is_locked ";

	global gLogFileName;
 
	set Status [unknown vlog -q -bl -xo$gLogFileName $ReposFilePath ];

	if {!$Status } \
	{
		set FileSize [file size $gLogFileName];
		rm $gLogFileName;
		if { $FileSize > 0 } {
			set Status 0;
		} else {
			set Status 1;
		}
	}

	return $Status;
}

##################################################################################
#  	SNiFF+ Call: pvcs_create_repository_dir 
#
#	Description: Create a directory for a repository.
#
#	SNiFF+	Adaptor		PVCS	Description
# 	------  ---------	----	--------------- 
#	%P 		ReposPath			Absoulte path to new archive 
#
##################################################################################

proc pvcs_create_repository_dir { ReposPath } \
{
	set _Fct "pvcs_create_repository_dir "; trace_var; 
	#puts stderr "@@@@  pvcs_create_repository_dir $ReposPath";

	set ReposPath [dirname $ReposPath];
	
	mkdir_p $ReposPath;
}

proc pvcs_test_tool {} \
{
	set _Fct "pvcs_test_tool "; trace_var; 
 
	global gPathVar;
 
	set Status [regexp -nocase {Pvcs} $gPathVar];
 
	if { $Status == 0 } { 
		return 1; 
	} else { 
	return 0;
	};
}

proc pvcs_constructor { T_TmpDir } \
{
	# puts stderr "@@@@  pvcs_constructor ";
 
	mkdir_p $T_TmpDir;
	return 0;	# XXX questionable
}

proc pvcs_destructor { T_TmpDir } \
{
	#puts stderr "@@@@  pvcs_destructor ";
 
	rm_r $T_TmpDir;
}

##################################################################################
#  	Adaptor Call:  set_config 
#
#	Description: Create a temporary configuration file in $WorkPath which contains 
#				 $Directive for this command only. It is up to the calling procedure 
#				 to delete the file before its finishes.
#
##################################################################################

proc set_config { UserID WorkPath Directive } \
{
	global TempPath gTempCfgFile;
	global gPlatform;

	switch $gPlatform {
		windows {
			regsub -all {\\} $Directive {\\\\} Directive;
		}
		unix {
			regsub -all {//} $Directive {/} Directive;
		}
	}

	set File [open $gTempCfgFile { WRONLY CREAT}];
	puts $File  "$Directive" ;
	puts $File  "VCSID $UserID" ;
	puts $File  "DateFormat yyyy/mm/ddd hh:mm:ss";

	close $File ;
}

#------ body ------------------------------------------------------------ 

if { [info global gDebug] == "" } {
	set gDebug 0;
}

trace_open;
trace_print "begin: argc=$argc argv=$argv";

set ReturnCode 0;
set BlockValue 0;
if { $argc > 0 } {
	set ReturnCode [catch {eval $argv} BlockValue]; 
} else {
	set ReturnCode 5;
}

trace_print "ReturnCode=$ReturnCode BlockValue=$BlockValue";
trace_print "end";
trace_close;
if { $ReturnCode == 0 } {
	exit $BlockValue ;
} else {
	exit 255;
}
 
